package com.ruoyi.exam.task;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.HashMap;
import java.util.Optional;

import javax.management.RuntimeErrorException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;

import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.exam.domain.entity.ExamPaper;
import com.ruoyi.exam.domain.entity.ExamPaperQuestion;
import com.ruoyi.exam.domain.entity.Question;
import com.ruoyi.exam.domain.entity.TTask;
import com.ruoyi.exam.domain.entity.TTaskExamPaper;
import com.ruoyi.exam.domain.entity.TTaskExe;
import com.ruoyi.exam.domain.entity.TWrongQuestion;
import com.ruoyi.exam.mapper.ExamPaperQuestionMapper;
import com.ruoyi.exam.mapper.QuestionMapper;
import com.ruoyi.exam.mapper.TTaskExamPaperMapper;
import com.ruoyi.exam.mapper.TTaskExeMapper;
import com.ruoyi.exam.mapper.TTaskMapper;
import com.ruoyi.exam.mapper.TWrongQuestionMapper;

@Component("dailyTask")
public class DailyTaskPaperGenerator {

    Logger logger = LoggerFactory.getLogger(DailyTaskPaperGenerator.class);

    @Autowired
    private TTaskMapper taskMapper;

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private ExamPaperQuestionMapper examPaperQuestionMapper;

    @Autowired
    private TWrongQuestionMapper tWrongQuestionMapper;

    @Autowired
    private TTaskExamPaperMapper taskExamPaperMapper;

    @Autowired
    private TTaskExeMapper taskExeMapper;

    /**
     * 每日一练试卷自动生成方法
     * 
     * 业务逻辑：
     * 1. 查询所有未过期的每日一练类型任务
     * 2. 对每个任务查询其关联的执行记录
     * 3. 如果存在执行记录，则为每个用户生成各自的试卷：
     * 3.1 针对每个用户收集生成的试卷，存入用户试卷映射表
     * 3.2 优先从用户错题集抽取题目，不足部分从题库随机抽取
     * 3.3 确保题目符合配置的题型、数量和分类要求
     * 4. 生成试卷后，一次性更新所有用户的任务执行记录
     * 
     * 定时执行策略：每天0点执行(当前已注释)
     */
    // @Scheduled(cron = "0 0 0 * * ?")
    @Transactional
    public void generateDailyTaskPaper() {
        // 1. 查询所有每日一练任务
        TTask queryTask = new TTask();
        queryTask.setType(1); // 每日一练类型
        List<TTask> allDailyTasks = taskMapper.selectTTaskList(queryTask).stream()
                .filter(task -> {
                    // 获取当前日期（不含时分秒）
                    Date today = DateUtils.parseDate(DateUtils.getDate());
                    // 获取任务结束日期（不含时分秒）
                    Date endDate = DateUtils
                            .parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, task.getEndTime()));
                    // 如果结束日期大于等于今天，则任务未过期
                    return !endDate.before(today);
                })
                .collect(Collectors.toList());
        // 2. 遍历任务，检查是否有执行记录
        String today = DateUtils.getDate();
        Date now = new Date();
        for (TTask task : allDailyTasks) {
            // 查询任务是否有执行记录
            TTaskExe queryExe = new TTaskExe();
            queryExe.setTaskId(task.getId());
            List<TTaskExe> exeList = taskExeMapper.selectTTaskExeList(queryExe);
            /**
             * exeList是task任务下的所有执行记录，包含已执行和未执行的
             * 所有的处理应该按照单个用户来处理，不能影响其他用户
             * 这里需要处理的逻辑是，用户的已执行的所有记录都要保存不能动
             * 未执行的记录只保留今天的最新一条，其他都删除
             * 如果今天不存在执行记录，则需要创建新的执行记录
             */
            if (!exeList.isEmpty()) {
                // 按用户分组处理执行记录
                Map<Long, List<TTaskExe>> userTaskMap = exeList.stream()
                        .collect(Collectors.groupingBy(TTaskExe::getUserId));

                // 处理每个用户的任务执行记录
                for (Map.Entry<Long, List<TTaskExe>> entry : userTaskMap.entrySet()) {
                    Long userId = entry.getKey();
                    List<TTaskExe> userExeList = entry.getValue();

                    // 将用户的执行记录分为已执行和未执行两类
                    List<TTaskExe> executedRecords = new ArrayList<>();
                    List<TTaskExe> unexecutedRecords = new ArrayList<>();

                    for (TTaskExe exe : userExeList) {
                        if (exe.getTaskStatus() == 1) {
                            executedRecords.add(exe); // 已执行的记录
                        } else {
                            unexecutedRecords.add(exe); // 未执行的记录
                        }
                    }

                    // 处理未执行的记录
                    if (!unexecutedRecords.isEmpty()) {
                        // 查找今天的记录
                        Optional<TTaskExe> todayRecord = unexecutedRecords.stream()
                                .filter(exe -> DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, exe.getBindTime())
                                        .equals(today))
                                .findFirst();

                        if (todayRecord.isPresent()) {
                            // 如果今天有记录，保留这条记录，删除其他未执行的记录
                            TTaskExe todayExe = todayRecord.get();
                            for (TTaskExe exe : unexecutedRecords) {
                                if (!exe.getId().equals(todayExe.getId())) {
                                    // 删除非今天的未执行记录
                                    taskExeMapper.deleteTTaskExeById(exe.getId());
                                }
                            }

                            // 为今天的记录生成试卷
                            TTaskExamPaper tTaskExamPaper = generatePaperForTask(task, todayExe);
                            if (tTaskExamPaper == null) {
                                throw new RuntimeException("生成试卷失败");
                            }

                            // 更新今天的任务执行记录
                            todayExe.setBindTime(now);
                            todayExe.setUpdateTime(now);
                            todayExe.setTaskExamPaperAnswerId(null);
                            todayExe.setDeleted(0);
                            taskExeMapper.updateTTaskExe(todayExe);
                        } else {
                            // 如果今天没有记录，删除所有未执行的记录，并创建一条新记录
                            for (TTaskExe exe : unexecutedRecords) {
                                taskExeMapper.deleteTTaskExeById(exe.getId());
                            }

                            // 创建新的任务执行记录
                            TTaskExe newExe = new TTaskExe();
                            newExe.setTaskId(task.getId());
                            newExe.setUserId(userId);
                            newExe.setBindTime(now);
                            newExe.setTaskStatus(0L); // 设置为未执行状态
                            newExe.setTaskExamPaperAnswerId(null);
                            newExe.setUpdateTime(now);
                            newExe.setCreateTime(now);
                            newExe.setDeleted(0);
                            taskExeMapper.insertTTaskExe(newExe);

                            // 为新记录生成试卷
                            TTaskExamPaper tTaskExamPaper = generatePaperForTask(task, newExe);
                            if (tTaskExamPaper == null) {
                                throw new RuntimeException("生成试卷失败");
                            }
                        }
                    } else {
                        // 如果该用户没有未执行的记录，创建一条新记录
                        TTaskExe newExe = new TTaskExe();
                        newExe.setTaskId(task.getId());
                        newExe.setUserId(userId);
                        newExe.setBindTime(now);
                        newExe.setTaskStatus(0L); // 设置为未执行状态
                        newExe.setTaskExamPaperAnswerId(null);
                        newExe.setUpdateTime(now);
                        newExe.setCreateTime(now);
                        newExe.setDeleted(0);
                        taskExeMapper.insertTTaskExe(newExe);

                        // 为新记录生成试卷
                        TTaskExamPaper tTaskExamPaper = generatePaperForTask(task, newExe);
                        if (tTaskExamPaper == null) {
                            throw new RuntimeException("生成试卷失败");
                        }
                    }
                }
            }
        }
    }

    /**
     * 更新任务执行记录
     * 
     * 业务逻辑：
     * 1. 查询指定任务的所有未执行记录
     * 2. 将任务执行记录按用户ID分组，为每个用户单独处理
     * 3. 对每个用户：
     * 3.1 检查该用户今天是否已有记录
     * 3.2 如果今天有记录，则更新该记录的绑定时间和试卷关联
     * 3.3 如果今天没有记录，则创建新的任务执行记录
     * 
     * 此方法确保每个用户在每天都有一个最新的任务执行记录，
     * 同时通过一次性处理所有用户提高了性能，避免重复操作数据库。
     * 
     * @param task         任务对象
     * @param userPaperMap 用户ID -> 试卷的映射
     * @param today        当天日期字符串
     * @param now          当前时间
     */
    private void updateTaskExeRecords(TTask task, Map<Long, TTaskExamPaper> userPaperMap, String today, Date now) {
        // 1. 查询该任务的所有执行记录，由于是新推进的任务，所以之前没执行的任务全部清除重建，已执行的保留
        TTaskExe queryExe = new TTaskExe();
        queryExe.setTaskId(task.getId());
        // queryExe.setTaskStatus(0L);
        List<TTaskExe> exeList = taskExeMapper.selectTTaskExeList(queryExe);

        // 按用户分组处理
        Map<Long, List<TTaskExe>> userTaskMap = exeList.stream()
                .collect(Collectors.groupingBy(TTaskExe::getUserId));

        // 更新每个用户的任务记录
        for (Map.Entry<Long, List<TTaskExe>> entry : userTaskMap.entrySet()) {
            Long userId = entry.getKey();
            List<TTaskExe> userExeList = entry.getValue();

            // 获取用户对应的试卷
            TTaskExamPaper userPaper = userPaperMap.get(userId);
            if (userPaper == null) {
                continue; // 如果没有为该用户生成试卷，跳过处理
            }
            // 删除该用户该任务的所有未执行记录
            for (TTaskExe userExeList2 : userExeList) {
                if (userExeList2.getTaskStatus() == 0) {
                    taskExeMapper.deleteTTaskExeById(userExeList2.getId());
                }
            }
            // 如果全用新增的话，因为id是自增的，因为上面已经生成过试卷并且绑定关系已经有了，所以这里就不太合适全部新建，会导致任务表的id无法关联试卷表，所以这里要判断一下，如果今天有记录，则更新绑定关系和时间，如果今天没有记录，则创建新记录
            // 查找该用户今天的记录
            Optional<TTaskExe> todayRecord = userExeList.stream()
                    .filter(exe -> DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, exe.getBindTime()).equals(today))
                    .findFirst();
            if (todayRecord.isPresent()) {
                // 如果今天已有记录，更新绑定关系和时间
                TTaskExe updateExe = todayRecord.get();
                updateExe.setBindTime(now);
                updateExe.setUpdateTime(now);
                updateExe.setTaskExamPaperAnswerId(null);
                updateExe.setDeleted(0);
                taskExeMapper.updateTTaskExe(updateExe);
            } else {
                // 如果今天没有记录，创建新记录
                TTaskExe newExe = new TTaskExe();
                newExe.setTaskId(task.getId());
                newExe.setUserId(userId);
                newExe.setBindTime(now);
                newExe.setTaskStatus(0L); // 设置为待完成状态
                newExe.setTaskExamPaperAnswerId(null); // 清空答卷ID
                newExe.setUpdateTime(now);
                newExe.setCreateTime(now);
                taskExeMapper.insertTTaskExe(newExe);
            }
        }
    }

    /**
     * 为指定任务和用户生成试卷
     * 
     * 业务逻辑：
     * 1. 解析任务的题型配置(QuestionConfig)：
     * - 题型及数量要求
     * - 题库分类要求
     * 2. 试题选择逻辑：
     * 2.1 优先从用户错题集中选择符合条件的题目：
     * - 匹配题型
     * - 匹配题库分类
     * - 不超过配置的数量
     * 2.2 如果错题集中题目不足，从题库中随机选择：
     * - 按题型逐个处理
     * - 通过questionMapper.selectRandomQuestions随机抽取题目
     * - 确保题目不重名
     * - 直到达到所需数量或无题可选
     * 3. 生成试卷对象：
     * - 设置名称为"每日一练-当前日期"
     * - 计算总分数
     * - 包含所有选择的题目
     * 4. 保存到任务试卷表：
     * - 先删除该用户可能存在的旧试卷
     * - 插入新试卷记录
     * 
     * 该方法确保为每个用户生成定制化的试卷，包含错题和随机题目的组合。
     *
     * @param task 任务对象
     * @param exe  任务执行记录对象(包含用户ID)
     * @return 生成的任务试卷对象，失败则返回null
     */
    @Transactional(timeout = 30, isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
    private TTaskExamPaper generatePaperForTask(TTask task, TTaskExe exe) {
        try {
            // 先删除今天可能存在的旧试卷，将删除操作提前，减少锁持有时间
            TTaskExamPaper existingPaper = taskExamPaperMapper.selectTTaskExamPaperByTaskExeId(exe.getId());
            if (existingPaper != null) {
                logger.info("删除任务执行ID:{}对应的旧试卷", exe.getId());
                int deleteResult = taskExamPaperMapper.deleteTTaskExamPaperByTaskExeId(exe.getId());
                logger.info("删除结果: {}", deleteResult);
            }

            // 1. 解析题型配置
            QuestionConfig questionConfig = JSON.parseObject(task.getQuestionConfig(), QuestionConfig.class);
            if (questionConfig == null) {
                throw new RuntimeException("每日一练配置项为空，请重新配置每日一练任务！");
            }
            List<QuestionConfig> configs = new ArrayList<>();
            configs.add(questionConfig);

            // 2. 根据配置随机抽取题目
            List<ExamPaperQuestion> paperQuestions = new ArrayList<>();
            long questionOrder = 1;
            Double score = 0d;
            for (QuestionConfig config : configs) {
                // 2.1 这里要先查询用户的错题集，先从错题中优先抽取题目
                TWrongQuestion tWrongQuestionParams = new TWrongQuestion();
                tWrongQuestionParams.setUserId(exe.getUserId());
                List<TWrongQuestion> tWrongQuestions = tWrongQuestionMapper
                        .selectTWrongQuestionList(tWrongQuestionParams);
                List<ExamPaperQuestion> wrongQuestions = new ArrayList<>();
                for (TWrongQuestion wrongQuestion : tWrongQuestions) {
                    ExamPaperQuestion examPaperQuestion;
                    // 将错题转换为题目，如果错题是每日一练的错题，则需要从question表中查询
                    if (wrongQuestion.getIsdaily() == 1) {
                        Question question = questionMapper.selectQuestionById(wrongQuestion.getQuestionId());
                        if (question == null) { // 试题表如果发生变更，会导致错题和题目不一致，所以这里需要判断一下
                            continue;
                        }
                        examPaperQuestion = convertQuestionToExamPaperQuestion(question, questionOrder++);
                    } else {
                        examPaperQuestion = examPaperQuestionMapper
                                .selectExamPaperQuestionById(wrongQuestion.getQuestionId());
                    }
                    if (examPaperQuestion != null) {
                        wrongQuestions.add(examPaperQuestion);
                    }
                }

                // 先从错题集中根据题型和分类ID查询题目，看看数量是否足够
                for (ExamPaperQuestion examPaperQuestion : wrongQuestions) {
                    if (config.getTypeCount().keySet().contains(examPaperQuestion.getQuestionType().toString())
                            && config.getTitleNames().contains(examPaperQuestion.getOutline())
                            && config.getTypeCount().get(
                                    examPaperQuestion.getQuestionType().toString()) > 0) {

                        paperQuestions.add(examPaperQuestion);
                        score = score + examPaperQuestion.getQuestionScore();
                        // 匹配到一个，就减去一个数量
                        config.getTypeCount().put(examPaperQuestion.getQuestionType().toString(),
                                config.getTypeCount().get(examPaperQuestion.getQuestionType().toString()) - 1);
                    }
                }

                // 2.2下面开始从数据库中查询题目
                // 构建查询条件
                Question queryQuestion = new Question();
                // 设置题型
                for (String typeId : config.getTypeCount().keySet()) {
                    if (config.getTypeCount().get(typeId) > 0) {
                        queryQuestion.setQuestionType(Long.parseLong(typeId));
                        int requiredCount = config.getTypeCount().get(typeId);
                        Set<String> existingTitles = new HashSet<>();
                        List<Question> selectedQuestions = new ArrayList<>();

                        // 设置最大尝试次数，防止死循环
                        int maxAttempts = 3;
                        int attempts = 0;

                        // 循环抽取直到达到所需数量或尝试次数达到上限
                        while (selectedQuestions.size() < requiredCount && attempts < maxAttempts) {
                            attempts++;

                            // 每次直接抽取所需总量的题目，而不是剩余数量
                            List<Question> questions = questionMapper.selectRandomQuestions(
                                    queryQuestion,
                                    requiredCount, // 直接抽取所需总量
                                    config.getTitleNames());

                            // 如果没有更多题目可抽，跳出循环
                            if (questions.isEmpty()) {
                                logger.info("题库中符合条件的题目数量不足，已抽取:{}道，需要:{}道",
                                        selectedQuestions.size(), requiredCount);
                                break;
                            }

                            // 过滤掉重名题目
                            for (Question question : questions) {
                                // 过滤掉空题目（异常数据）
                                if ("[]".equals(question.getQuestionText()) || "".equals(question.getQuestionText())
                                        || question.getQuestionText() == null) {
                                    continue;
                                }
                                if (!existingTitles.contains(question.getQuestionTitle())) {
                                    existingTitles.add(question.getQuestionTitle());
                                    selectedQuestions.add(question);

                                    // 如果已达到所需数量，提前退出循环
                                    if (selectedQuestions.size() >= requiredCount) {
                                        break;
                                    }
                                }
                            }

                            // 如果第一次获取的题目数量 + 已选题目数量 < 所需数量，说明题库中可能没有足够的不重复题目
                            if (attempts == 1 && (questions.size() + selectedQuestions.size() < requiredCount)) {
                                logger.warn("题库中题目总数可能不足，当前题型:{}，需要:{}道，实际可用约:{}道",
                                        typeId, requiredCount, questions.size());
                                break;
                            }
                        }

                        // 如果题目不足，记录日志
                        if (selectedQuestions.size() < requiredCount) {
                            logger.warn("无法获取足够的题目，题型:{}，需要:{}道，实际获取:{}道",
                                    typeId, requiredCount, selectedQuestions.size());
                        }

                        // 将筛选后的题目转换为试卷题目
                        for (Question question : selectedQuestions) {
                            ExamPaperQuestion paperQuestion = convertQuestionToExamPaperQuestion(question,
                                    questionOrder++);
                            paperQuestions.add(paperQuestion);
                            score = score + question.getQuestionScore();
                        }
                    }
                }
            }

            // 3. 生成试卷
            ExamPaper examPaper = new ExamPaper();
            examPaper.setName("每日一练-" + DateUtils.getDate());
            examPaper.setCreateTime(new Date());
            examPaper.setUpdateTime(new Date());
            examPaper.setExamPaperQuestions(paperQuestions);
            examPaper.setScore(score);

            // 4. 保存到任务试卷表
            TTaskExamPaper taskExamPaper = new TTaskExamPaper();
            taskExamPaper.setTaskId(task.getId());
            taskExamPaper.setTaskExeId(exe.getId());
            taskExamPaper.setPaperContent(JSON.toJSONString(examPaper));
            taskExamPaper.setCreateTime(new Date());
            taskExamPaper.setUpdateTime(new Date());

            // 5. 插入新试卷，删除操作已在方法开始时执行
            taskExamPaperMapper.insertTTaskExamPaper(taskExamPaper);

            return taskExamPaper;

        } catch (Exception e) {
            // 记录日志
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将Question对象转换为ExamPaperQuestion对象
     * 
     * 业务逻辑：
     * 1. 复制Question的所有相关属性到ExamPaperQuestion对象
     * 2. 设置题目排序号
     * 3. 设置创建和更新时间
     * 
     * @param question      原始题目对象
     * @param questionOrder 题目排序号
     * @return 转换后的试卷题目对象
     */
    private ExamPaperQuestion convertQuestionToExamPaperQuestion(Question question, long questionOrder) {
        ExamPaperQuestion paperQuestion = new ExamPaperQuestion();
        paperQuestion.setQuestionType(question.getQuestionType());
        paperQuestion.setQuestionTitle(question.getQuestionTitle());
        paperQuestion.setQuestionText(question.getQuestionText());
        paperQuestion.setQuestionAnswer(question.getQuestionAnswer());
        paperQuestion.setQuestionAnswerExplain(question.getQuestionAnswerExplain());
        paperQuestion.setQuestionScore(question.getQuestionScore());
        paperQuestion.setSort(questionOrder++);
        paperQuestion.setCreateTime(new Date());
        paperQuestion.setUpdateTime(new Date());
        paperQuestion.setId(question.getId());
        paperQuestion.setDifficult(question.getDifficult());
        paperQuestion.setOutline(question.getOutline());
        return paperQuestion;
    }

    /**
     * 手动触发生成每日一练试卷
     * 
     * 业务逻辑：
     * 1. 如果指定了特定任务ID：
     * 1.1 查询指定任务，检查是否为每日一练类型(type=1)
     * 1.2 检查任务是否已过期(结束日期<今天)
     * 1.3 查询任务的执行记录
     * 1.4 如有执行记录，为每个用户生成试卷：
     * - 调用generatePaperForTask生成用户试卷
     * - 收集所有用户的试卷映射
     * 1.5 一次性更新所有用户的任务执行记录
     * 2. 如果未指定任务ID(为null)：
     * 2.1 调用generateDailyTaskPaper()处理所有未过期的每日一练任务
     * 
     * 该方法支持手动触发生成试卷，可针对单个任务或所有任务操作，
     * 并通过日志记录执行过程，便于问题排查。
     * 
     * @param taskId 指定任务ID，如果为null则处理所有未过期的每日一练任务
     */
    @Transactional
    public void generateDailyTaskPaperManually(Long taskId) {
        logger.info("手动触发生成每日一练试卷:{}", taskId);
        if (taskId != null) {
            // 处理指定任务
            TTask task = taskMapper.selectTTaskById(taskId);
            logger.info("获取任务:{}", task);
            if (task != null && task.getType() == 1) {
                // 检查任务是否过期
                Date today = DateUtils.parseDate(DateUtils.getDate());
                Date endDate = DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, task.getEndTime()));
                if (!endDate.before(today)) {
                    logger.info("任务未过期");
                    // 查询任务是否有执行记录
                    TTaskExe queryExe = new TTaskExe();
                    queryExe.setTaskId(task.getId());
                    List<TTaskExe> exeList = taskExeMapper.selectTTaskExeList(queryExe);

                    // 如果有执行记录，则生成试卷并更新执行记录
                    if (!exeList.isEmpty()) {
                        logger.info("有执行记录");

                        // 按用户分组处理执行记录
                        Map<Long, List<TTaskExe>> userTaskMap = exeList.stream()
                                .collect(Collectors.groupingBy(TTaskExe::getUserId));

                        // 处理每个用户的任务执行记录
                        for (Map.Entry<Long, List<TTaskExe>> entry : userTaskMap.entrySet()) {
                            Long userId = entry.getKey();
                            List<TTaskExe> userExeList = entry.getValue();

                            // 将用户的执行记录分为已执行和未执行两类
                            List<TTaskExe> executedRecords = new ArrayList<>();
                            List<TTaskExe> unexecutedRecords = new ArrayList<>();

                            for (TTaskExe exe : userExeList) {
                                if (exe.getTaskStatus() == 1) {
                                    executedRecords.add(exe); // 已执行的记录
                                } else {
                                    unexecutedRecords.add(exe); // 未执行的记录
                                }
                            }

                            String todayStr = DateUtils.getDate();

                            // 处理未执行的记录
                            if (!unexecutedRecords.isEmpty()) {
                                // 查找今天的记录
                                Optional<TTaskExe> todayRecord = unexecutedRecords.stream()
                                        .filter(exe -> DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, exe.getBindTime())
                                                .equals(todayStr))
                                        .findFirst();

                                if (todayRecord.isPresent()) {
                                    // 如果今天有记录，保留这条记录，删除其他未执行的记录
                                    TTaskExe todayExe = todayRecord.get();
                                    for (TTaskExe exe : unexecutedRecords) {
                                        if (!exe.getId().equals(todayExe.getId())) {
                                            // 删除非今天的未执行记录
                                            taskExeMapper.deleteTTaskExeById(exe.getId());
                                        }
                                    }

                                    // 为今天的记录生成试卷
                                    TTaskExamPaper tTaskExamPaper = generatePaperForTask(task, todayExe);
                                    if (tTaskExamPaper == null) {
                                        throw new RuntimeException("生成试卷失败");
                                    }

                                    // 更新今天的任务执行记录
                                    todayExe.setBindTime(today);
                                    todayExe.setUpdateTime(today);
                                    todayExe.setTaskExamPaperAnswerId(null);
                                    todayExe.setDeleted(0);
                                    taskExeMapper.updateTTaskExe(todayExe);
                                } else {
                                    // 如果今天没有记录，删除所有未执行的记录，并创建一条新记录
                                    for (TTaskExe exe : unexecutedRecords) {
                                        taskExeMapper.deleteTTaskExeById(exe.getId());
                                    }

                                    // 创建新的任务执行记录
                                    TTaskExe newExe = new TTaskExe();
                                    newExe.setTaskId(task.getId());
                                    newExe.setUserId(userId);
                                    newExe.setBindTime(today);
                                    newExe.setTaskStatus(0L); // 设置为未执行状态
                                    newExe.setTaskExamPaperAnswerId(null);
                                    newExe.setUpdateTime(today);
                                    newExe.setCreateTime(today);
                                    newExe.setDeleted(0);
                                    taskExeMapper.insertTTaskExe(newExe);

                                    // 为新记录生成试卷
                                    TTaskExamPaper tTaskExamPaper = generatePaperForTask(task, newExe);
                                    if (tTaskExamPaper == null) {
                                        throw new RuntimeException("生成试卷失败");
                                    }
                                }
                            } else {
                                // 如果该用户没有未执行的记录，创建一条新记录
                                TTaskExe newExe = new TTaskExe();
                                newExe.setTaskId(task.getId());
                                newExe.setUserId(userId);
                                newExe.setBindTime(today);
                                newExe.setTaskStatus(0L); // 设置为未执行状态
                                newExe.setTaskExamPaperAnswerId(null);
                                newExe.setUpdateTime(today);
                                newExe.setCreateTime(today);
                                newExe.setDeleted(0);
                                taskExeMapper.insertTTaskExe(newExe);

                                // 为新记录生成试卷
                                TTaskExamPaper tTaskExamPaper = generatePaperForTask(task, newExe);
                                if (tTaskExamPaper == null) {
                                    throw new RuntimeException("生成试卷失败");
                                }
                            }
                        }
                    }
                }
            }
        } else {
            // 处理所有任务
            generateDailyTaskPaper();
        }
    }

    // 题型配置类
    static class QuestionConfig {
        // 人员类型列表
        private List<String> peopleTypes;

        // 题库名称列表
        private List<String> titleNames;

        // 题型数量配置 key:题型ID, value:题目数量
        private Map<String, Integer> typeCount;

        // getter和setter
        public List<String> getPeopleTypes() {
            return peopleTypes;
        }

        public void setPeopleTypes(List<String> peopleTypes) {
            this.peopleTypes = peopleTypes;
        }

        public List<String> getTitleNames() {
            return titleNames;
        }

        public void setTitleNames(List<String> titleNames) {
            this.titleNames = titleNames;
        }

        public Map<String, Integer> getTypeCount() {
            return typeCount;
        }

        public void setTypeCount(Map<String, Integer> typeCount) {
            this.typeCount = typeCount;
        }
    }
}